"use strict";

(function($) {
	jQuery.fn.extend({
		highlight : function(pat) {

			function innerHighlight(node, pat) {
				var skip = 0;
				if (node.nodeType == 3) {
					var pos = node.data.toUpperCase().indexOf(pat);
					if (pos >= 0) {
						var spannode = document.createElement('span');
						spannode.className = 'highlight';
						var middlebit = node.splitText(pos);
						var endbit = middlebit.splitText(pat.length);
						var middleclone = middlebit.cloneNode(true);
						spannode.appendChild(middleclone);
						middlebit.parentNode.replaceChild(spannode, middlebit);
						skip = 1;
					}
				} else if (node.nodeType == 1 && node.childNodes && !/(script|style)/i.test(node.tagName)) {
					for ( var i = 0; i < node.childNodes.length; ++i) {
						i += innerHighlight(node.childNodes[i], pat);
					}
				}
				return skip;
			}
			return this.length && pat && pat.length ? this.each(function() {
				innerHighlight(this, pat.toUpperCase());
			}) : this;

		}
	});

})(jQuery);

(function($) {
	jQuery.fn.extend({
		elastic : function() {

			var mimics = [ 'paddingTop', 'paddingRight', 'paddingBottom', 'paddingLeft', 'fontSize', 'lineHeight', 'fontFamily', 'width', 'fontWeight', 'border-top-width', 'border-right-width', 'border-bottom-width', 'border-left-width', 'borderTopStyle', 'borderTopColor', 'borderRightStyle', 'borderRightColor', 'borderBottomStyle', 'borderBottomColor', 'borderLeftStyle', 'borderLeftColor' ];

			return this.each(function() {

				if (this.type !== 'textarea') {
					return false;
				}

				var $textarea = jQuery(this), $twin = jQuery('<div />').css({
					'position' : 'absolute',
					'display' : 'none',
					'word-wrap' : 'break-word',
					'white-space' : 'pre-wrap'
				}), lineHeight = parseInt($textarea.css('line-height'), 10) || parseInt($textarea.css('font-size'), '10'), minheight = parseInt($textarea.css('height'), 10) || lineHeight * 3, maxheight = parseInt($textarea.css('max-height'), 10) || Number.MAX_VALUE, goalheight = 0;

				if (maxheight < 0) {
					maxheight = Number.MAX_VALUE;
				}

				$twin.appendTo($textarea.parent());

				var i = mimics.length;
				while (i--) {
					$twin.css(mimics[i].toString(), $textarea.css(mimics[i].toString()));
				}

				function setTwinWidth() {
					var curatedWidth = Math.floor(parseInt($textarea.width(), 10));
					if ($twin.width() !== curatedWidth) {
						$twin.css({
							'width' : curatedWidth + 'px'
						});

						update(true);
					}
				}

				function setHeightAndOverflow(height, overflow) {

					var curratedHeight = Math.floor(parseInt(height, 10));
					if ($textarea.height() !== curratedHeight) {
						$textarea.css({
							'height' : curratedHeight + 'px',
							'overflow' : overflow
						});
					}
				}

				function update(forced) {

					var textareaContent = $textarea.val().replace(/&/g, '&amp;').replace(/ {2}/g, '&nbsp;').replace(/<|>/g, '&gt;').replace(/\n/g, '<br />');

					var twinContent = $twin.html().replace(/<br>/ig, '<br />');

					if (forced || textareaContent + '&nbsp;' !== twinContent) {

						$twin.html(textareaContent + '&nbsp;');

						if (Math.abs($twin.height() + lineHeight - $textarea.height()) > 3) {

							var goalheight = $twin.height() + lineHeight;
							if (goalheight >= maxheight) {
								setHeightAndOverflow(maxheight, 'auto');
							} else if (goalheight <= minheight) {
								setHeightAndOverflow(minheight, 'hidden');
							} else {
								setHeightAndOverflow(goalheight, 'hidden');
							}

						}

					}

				}

				$textarea.css({
					'overflow' : 'hidden'
				});

				$textarea.bind('keyup change cut paste', function() {
					update();
				});

				$textarea.bind('update', update);

				$textarea.bind('input paste', function(e) {
					setTimeout(update, 250);
				});

				update();

			});

		}
	});
})(jQuery);